package characteristics.inheritance;

import bean.*;
import org.junit.Test;

/**
 * 继承性
 * 好处：
 * 继承的出现减少了代码冗余，提高了代码的复用性；
 * 继承的出现，更有利于功能的扩展。
 * <p>
 * 子类继承父类之后，
 * 子类就获取到了父类中声明的所有的属性和方法
 * 但是，由于封装性的影响，可能子类不能直接调用父类中声明的属性或方法。
 * <p>
 * 方法的重写(overwrite/override)
 * 子类对父类继承过来的方法进行覆盖、覆写的操作，就称为方法的重写
 * 重写应该遵循的规则：
 * - 父类被重写的方法与子类重写的方法的方法名和形参列表必须相同。
 * - 子类重写的方法的权限修饰符不小于被重写的方法的权限修饰符。
 * -   > 子类不能重写父类中声明为private的方法
 * - 返回值类型：
 * > 父类被重写的方法的返回值类型是void，则子类重写的方法的返回值类型必须是void；
 * > 父类被重写的方法的返回值类型是基本数据类型，则子类重写的方法的返回值类型必须与被重写的方法的返回值类型相同；
 * > 父类被重写的方法的返回值类型是引用数据类型，则子类重写的方法的返回值类型可以与被重写的方法的返回值类型相同
 * -----或是被重写的方法的返回值类型的子类；
 * <p>
 * "super(形参列表)"，必须声明在构造器的首行。
 * 在通过子类的构造器创建对象时，一定在调用子类构造器的过程中，直接或间接的调用到父类的构造器。
 * 也正因为调用过父类的构造器，才会将父类中声明的属性和方法加载到内存中，供子类使用。
 * <p>
 * 子类对象实例化全过程
 * 1.从结果的角度看：体现为类的继承性
 * 当创建在子类对象后，子类对象就获取了其父类中声明的所有的属性和方法，在权限允许的情况下，可以直接调用。
 * 2.从过程的角度看：
 * 当通过子类的构造器创建对象时，子类构造器一定会直接或间接的调用到其父类的构造器，而其父类的构造器同样会直接或间接调用到其父类的父类的构造器，
 * ...直到调用到Object类的构造器。
 **/

public class InheritanceTest {
    @Test
    public void testNewStudent() {
        Student student = new Student("张三", 12, 5, 98);
        System.out.println(student);
        student.setName("张三三");
        student.setNumber(1);
        System.out.println(student);

        // 获取student所属类的父类
        System.out.println(student.getClass());
        System.out.println(student.getClass().getSuperclass());

        // Java中声明的类，如果没有显式声明其父类，则默认继承于 java.lang.Object
        // class java.lang.Object
        System.out.println(student.getClass().getSuperclass().getSuperclass());
    }

    @Test
    public void testManKind() {
        Kids kid1 = new Kids(12);
        Kids kid2 = new Kids(1, 0, 10);

        System.out.println(kid1);
        System.out.println(kid2);
        kid1.manOrWoman();
        kid2.employed();
    }

    @Test
    public void testCircle() {
        Cylinder cylinder = new Cylinder(2, 3);
        System.out.println(cylinder);
        System.out.println(cylinder.findVolume());
        Circle circle = new Circle(2);
        System.out.println(circle.findArea());
        System.out.println(cylinder.findArea());
//        Cylinder cylinder1 = new Cylinder(2);
    }

    @Test
    public void testOverride() {
        new Student().eat();
        new Person().eat();
        Student.swim();
    }

    @Test
    public void testAccount() {
        Account account = new Account(20000, 0.045);
        account.withdraw(30000);
        account.deposit(3000);
        account.withdraw(2500);
        System.out.println("余额为：" + account.getBalance() + "元。月利率为：" + account.getMonthlyInterest());

        System.out.println("---------------------");
        CheckAccount checkAccount = new CheckAccount(20000, 0.045, 5000);
        checkAccount.withdraw(5000);
        System.out.println("当前可透支额度为：" + checkAccount.getOverdraft() + "元。");
        checkAccount.withdraw(18000);
        System.out.println("当前可透支额度为：" + checkAccount.getOverdraft() + "元。");
        checkAccount.withdraw(3000);

        System.out.println(account);
        System.out.println(checkAccount);

    }
}
